package app.modules.infrastructure.lov.business.service;

import app.modules.common.enums.EnableFlagEnum;
import app.modules.common.exception.UnauthorizedDataAccessException;
import app.modules.common.exception.UnauthorizedDataCreateException;
import app.modules.infrastructure.lov.constant.LovMsgConstants;
import app.modules.infrastructure.lov.dto.web.WebValueItemDTO;
import app.modules.infrastructure.lov.dto.web.WebValueItemQueryDTO;
import app.modules.infrastructure.lov.dto.web.WebValueItemSaveDTO;
import app.modules.infrastructure.lov.dto.web.WebValueItemUpdateDTO;
import app.modules.infrastructure.lov.persistence.dao.ValueItemDAO;
import app.modules.infrastructure.lov.persistence.dao.ValueSetDAO;
import app.modules.infrastructure.lov.persistence.entity.ValueItemEO;
import app.modules.infrastructure.lov.persistence.entity.ValueSetEO;
import app.modules.infrastructure.lov.util.conversion.ValueItemConvertUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jasmine.framework.common.exception.BusinessException;
import jasmine.framework.common.exception.DataNotFoundException;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.common.util.I18nUtil;
import jasmine.framework.common.util.MapperUtil;
import jasmine.framework.common.util.NewUtil;
import jasmine.framework.common.util.ObjectUtil;
import jasmine.framework.context.CurrentSubject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;

/**
 * @author mh.z
 */
@Service
public class ValueItemService implements IValueItemService {
    private ValueItemDAO valueItemDAO;
    private ValueSetDAO valueSetDAO;

    public ValueItemService(ValueItemDAO valueItemDAO, ValueSetDAO valueSetDAO) {
        this.valueItemDAO = valueItemDAO;
        this.valueSetDAO = valueSetDAO;
    }

    /**
     * 分页查询值项
     *
     * @param queryDTO
     * @param page
     * @return
     */
    public List<WebValueItemDTO> pageWebValueItemDTOsByCond(WebValueItemQueryDTO queryDTO, Page page) {
        CheckUtil.notNull(queryDTO, "queryDTO null");
        CheckUtil.notNull(page, "page null");

        List<WebValueItemDTO> recordList = valueItemDAO.pageWebValueItemDTOsByCond(queryDTO, page);
        populateWebValueItemDTO(recordList);

        return recordList;
    }

    /**
     * 填充数据
     *
     * @param records
     */
    protected void populateWebValueItemDTO(List<WebValueItemDTO> records) {
        if (CollectionUtil.isEmpty(records)) {
            return;
        }

        records.forEach((record) -> {
            EnableFlagEnum enableFlagEnum = EnableFlagEnum.parseValue(record.getEnableFlag());
            record.setEnableFlagDesc(I18nUtil.getMessage(enableFlagEnum));
        });
    }

    /**
     * 查找指定 ID 的记录
     *
     * @param id
     * @return
     */
    public WebValueItemDTO getWebValueItemDtoById(Long id) {
        CheckUtil.notNull(id, "id null");

        ValueItemEO valueItemEO = valueItemDAO.getById(id);
        WebValueItemDTO webValueItemDTO = ValueItemConvertUtil.valueItemEO2WebValueItemDTO(valueItemEO);
        populateWebValueItemDTO(Collections.singletonList(webValueItemDTO));

        return webValueItemDTO;
    }

    /**
     * 保存记录
     *
     * @param saveDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public WebValueItemDTO saveValueItem(WebValueItemSaveDTO saveDTO) {
        CheckUtil.notNull(saveDTO, "saveDTO null");
        Long valueSetId = CheckUtil.notNull(saveDTO.getValueSetId(),
                "saveDTO.valueSetId null");

        String valueItemCode = saveDTO.getValueCode();
        long valueItemCodeCount = valueItemDAO.countByValueCode(valueSetId, valueItemCode, null);

        if (valueItemCodeCount > 0) {
            throw new BusinessException(LovMsgConstants.THE_VALUE_ITEM_CODE_ALREADY_EXISTS,
                    NewUtil.array(valueItemCode));
        }

        ValueSetEO valueSetEO = valueSetDAO.getById(valueSetId);
        if (valueSetEO == null) {
            throw new DataNotFoundException(ValueSetEO.class, valueSetId);
        }

        if (ObjectUtil.notEqual(valueSetEO.getTenantId(), CurrentSubject.getTenantId())) {
            throw new UnauthorizedDataCreateException()
                    .withErrorDetail(ValueItemEO.class, null);
        }

        ValueItemEO ValueItemEO = new ValueItemEO();
        MapperUtil.mapFields(saveDTO, ValueItemEO);
        ValueItemEO.setTenantId(CurrentSubject.getTenantId());
        // 保存记录
        valueItemDAO.save(ValueItemEO);

        return getWebValueItemDtoById(ValueItemEO.getId());
    }

    /**
     * 更新记录
     *
     * @param updateDTO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public WebValueItemDTO updateValueItem(WebValueItemUpdateDTO updateDTO) {
        CheckUtil.notNull(updateDTO, "updateDTO null");
        Long id = CheckUtil.notNull(updateDTO.getId(), "updateDTO.id null");
        Long valueSetId = CheckUtil.notNull(updateDTO.getValueSetId(),
                "saveDTO.valueSetId null");

        String valueItemCode = updateDTO.getValueCode();
        long valueItemCodeCount = valueItemDAO.countByValueCode(valueSetId, valueItemCode,
                Collections.singletonList(id));
        if (valueItemCodeCount > 0) {
            throw new BusinessException(LovMsgConstants.THE_VALUE_ITEM_CODE_ALREADY_EXISTS,
                    NewUtil.array(valueItemCode));
        }

        ValueItemEO valueItemEO = valueItemDAO.getById(id);
        if (valueItemEO == null) {
            throw new DataNotFoundException(ValueItemEO.class, id);
        }

        if (ObjectUtil.notEqual(valueItemEO.getTenantId(), CurrentSubject.getTenantId())) {
            throw new UnauthorizedDataAccessException()
                    .withErrorDetail(ValueItemEO.class, id, null);
        }

        MapperUtil.mapFields(updateDTO, valueItemEO);
        // 更新记录
        valueItemDAO.strictUpdateById(valueItemEO);

        return getWebValueItemDtoById(id);
    }

}
